unit Setup;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  ExtCtrls, EditBtn, StdCtrls, Buttons, ButtonPanel, inifiles, Grids;
  
const
      Lookup = 0;
      IsAnswer = 1;
      QuestionNo = 2;
      LineType = 3;
      Correct = 4;
      Detail = 5;
      Choice = 6;
      Score = 7; 

type
  
  { TSetupForm }

  TSetupForm = class ( TForm ) 
   BitBtn1 : TBitBtn;
   BitBtn2 : TBitBtn;
    bxPassword : TLabeledEdit;
    bxName : TEdit;
    bxPosition : TEdit;
    bxTime : TEdit;
    Label1 : TLabel;
    Label2 : TLabel;
    Label3 : TLabel;
    Label4 : TLabel;
    bxQuestionCount : TLabeledEdit;
    bxAnswerCount : TLabeledEdit;
    bxCorrectCount : TLabeledEdit;
    bxMin : TLabeledEdit;
    bxMax : TLabeledEdit;
    bxMid : TLabeledEdit;
    bxRed : TLabeledEdit;
    bxOrange : TLabeledEdit;
    bxGreen : TLabeledEdit;
    bxLegend : TLabeledEdit;
    Panel1 : TPanel;
    Panel2 : TPanel;
    Panel3 : TPanel;
    SelectDirectoryDialog1 : TSelectDirectoryDialog;
    procedure BitBtn1Click ( Sender : TObject ) ;
    procedure bxLegendChange ( Sender : TObject ) ;
    procedure bxRedExit ( Sender : TObject ) ;
    procedure CancelButtonClick ( Sender : TObject ) ;
    procedure chkLockChange ( Sender : TObject ) ;
    procedure FormActivate ( Sender : TObject ) ;
    procedure FormClose ( Sender : TObject; var CloseAction : TCloseAction ) ;
    procedure OKButtonClick ( Sender : TObject ) ;
    procedure SpeedButton1Click ( Sender : TObject ) ;
    procedure FormShow(modal : boolean = True);
  private
    { private declarations }
  public
    { public declarations }
    cancelled : boolean;
  end; 
  
  function min(a,b:integer):integer;

var
    SetupForm : TSetupForm; 
    QuestionCount, 
     c, // correct answer (of row)
    qc, // Question Count
    ac, // Answer Count
    ca, // Correct Answer Count
    mins, // Minimum score
    maxs, // Maximum Score
    minadd,  // Adding off the min score
    Red,
    Orange,
    Green 
    : integer;
    midscore // Middle score
    : double;
    CSVFilename : String; 

function encrypt(aString : String):String;

implementation


{ TSetupForm }

function min(a,b:integer):integer;
begin
  if a <= b then min := a else min := b;
end;

Function Encrypt(aString : String):String;
var Seed : longint;
    i, k  : integer;
    EncryptLength : integer;
begin
  seed := 0;

  // Get the seed
  for i := 1 to length(aString) do
    Seed := ord(aString[i]);

  // Randomize for the non-random password seed
  RandSeed := Seed;

  // Get the length of the encrypt string
  EncryptLength := 32;
  while length(aString) > EncryptLength do EncryptLength:= EncryptLength*2;

  // Add "junk" to the end of the password
  k := length(aString);
  for i := k+1 to EncryptLength do
    aString := aString + chr(random(256)+1);

  // Add a random amount to each char.
  // But remember that some characters will mess up if saved in a .ini file7
  for i := 1 to length(aString) do
    aString[i] := chr( (ord(aString[i])+random(256)) mod 94 + 33 );

  Encrypt := aString;
end;

procedure TSetupForm.OKButtonClick ( Sender : TObject ) ;
var allfine : boolean;
    spot : integer;
    ini : TInifile; 
begin
   
  Red := strtointdef(bxRed.Text,0);
  Orange := strtointdef(bxOrange.text,0);
  Green := strtointdef(bxGreen.text,0);
  
  Spot:= 100;
  
  AllFine := true;
  AllFine := AllFine and (bxName.text <> '');
  if not AllFine then Spot := 1;
  AllFine := AllFine and (bxPosition.text <> '');
  if not AllFine then Spot := min(spot,2);
  //AllFine := AllFine and (DirectoryExists(bxTime.text));
  //if not AllFine then Spot := min(spot,3);
  AllFine := AllFine and (red >= mins);
  if not AllFine then Spot := min(spot,4);
  AllFine := AllFine And (red < Green) and (red <= Orange);
  if not AllFine then Spot := min(spot,5);
  AllFine := AllFine and (Orange < Green);
  if not AllFine then Spot := min(spot,6);
  AllFine := AllFine and (Green <= Maxs);
  if not AllFine then Spot := min(spot,7);
  
  
  if not allfine then begin
    case Spot of
    1:ShowMessage('Please enter a Test Name');
    2:ShowMessage('Please enter a Position');
    3:ShowMessage('Please enter a Valid save path');
    4:ShowMessage('Please ensure that the Red score is greater or equal to the minimum score');
    5:ShowMessage('Please ensure that the Red score is less than the Orange and Green scores');
    6:ShowMessage('Please ensure that the Orange score is less than the Green score');
    7:ShowMessage('Please ensure that the Green Score is less than or equal to the Maximum score');
    else ShowMessage('You answers failed the validation unexpectedly');
    end;
    exit;
  end;
   
  ini := TInifile.Create('Settings.ini');
    
  ini.WriteInteger('General','Red',Red);
  ini.WriteInteger('General','Orange',Orange);
  ini.WriteInteger('General','Green',Green);
  ini.WriteString('General','Name',bxName.text);
  ini.WriteString('General','Position',bxPosition.text);
  ini.WriteString('General','Time',bxTime.text);
  ini.WriteString('General','LegendText',bxLegend.text);
  ini.WriteString('General','Password',Encrypt(bxPassword.Text));

  ini.free;
   
  

  cancelled := false;
  close;  
end;

procedure TSetupForm.SpeedButton1Click ( Sender : TObject ) ;
begin
  if selectdirectorydialog1.Execute then 
    bxTime.text := SelectDirectoryDialog1.FileName ;
end;

procedure TSetupForm.CancelButtonClick ( Sender : TObject ) ;
begin
  // Close without saving
  // TODO: Warn then 
  close; 
end;

procedure TSetupForm.chkLockChange ( Sender : TObject ) ;
begin
  //bxPassword.Visible := chkLock.Checked;
end;

procedure TSetupForm.FormActivate ( Sender : TObject ) ;
begin
end;

procedure TSetupForm.FormClose ( Sender : TObject; 
 var CloseAction : TCloseAction ) ;
begin

end;

procedure TSetupForm.bxRedExit ( Sender : TObject ) ;
begin

end;

procedure TSetupForm.BitBtn1Click ( Sender : TObject ) ;
begin
  // Close without saving
  // TODO: Warn then 
  close;  
end;

procedure TSetupForm.bxLegendChange ( Sender : TObject ) ;
begin

end;

procedure TSetupForm.FormShow(modal : boolean = True);
var i, row, col: integer;  // iterator
    pwd : string;
    rows : TStringList; 
    cols : TStringList;
    Test : TStringGrid; 
begin

{  if (locked) or (mainform.MainPanel.Visible) then  begin
    pwd := PasswordBox('ABC Questionnaire','Password:');
    addlog(pwd);
    addlog(encrypt(pwd));
    addlog(password);
    if encrypt(pwd) <> Password then exit;
  end;
} 
  Cancelled := false;

  bxName.text     := ''; 
  bxPosition.text := ''; 
  bxTime.Text := '';
  bxRed.text := '';
  bxOrange.text := '';
  bxGreen.text := '';
  bxLegend.Text := 
    'RATING SCALE:  1 - Extremely unlikely; 2 - Very unlikely; 3 - Somewhat unlikely; ' +
    '4 - Somewhat likely; 5 - Very likely; 6 - Extremely likely'; 
//  chklock.Checked := locked;
//  if locked then begin
//    bxPassword.Visible := true;
//    bxPassword.text := pwd;
//  end;
  
  rows := TStringList.Create; 
  cols := TStringList.Create;
  Test := TStringGrid.Create(nil); 
  // Loading the file    
  // rows.LoadFromFile(Path + PathDelim + TestName + '.csv');  
  rows.LoadFromFile(CSVFileName);
    
  // Converting the file into a StringGrid 
  Test.RowCount := rows.count; 
  for row := 0 to rows.Count -1 do begin
    cols.CommaText := Rows[row];
    if Test.ColCount < Cols.Count then Test.Colcount := Cols.count; 
    for col := 0 to Cols.Count - 1 do 
      Test.Cells[col,row] := cols[col];
  end;

  // +1 for the selected answer, and another +1 for the points allocated
  Test.ColCount := Test.ColCount + 2;
       
  // Set the amount of questions.  THIS ASSUMES that the questions has been set sequencially 
  QuestionCount := strtoint(Test.Cells[2,rows.Count-1]);

  qc := QuestionCount;
  ac := 0;
  ca := 0;
  mins := 0;
  maxs :=0;
  midscore := 0;
  
  for i := 0 to Test.RowCount -1 do 
  begin
    // We only want to work with answers
    if lowercase(Test.Cells[IsAnswer,i]) = 'true' then 
    begin 
      inc(ac);
      if Test.Cells[Correct,i] <> '' then inc(ca);
      c := strtointdef(Test.Cells[Correct,i],0);
      
      // If we don't have a correct answer then we continue to the next Q
      if c = 0 then continue;
      case c of 
      1 : minadd := 1;
      2 : minadd := 2;
      3 : minadd := 3;
      4 : minadd := 3;
      5 : minadd := 2;
      6 : minadd := 1;
      end;
      mins := mins + minadd ;
      midscore := midscore + ( 6 - abs(c-3.5));
    end;
  end;
  
  // Max score is 6 x the amount of answers
  maxs := ca * 6;
  
  bxQuestionCount.text := inttostr(qc);
  bxAnswerCount.text   := inttostr(ac);
  bxCorrectCount.text  := inttostr(ca);
  bxMin.text           := inttostr(mins);
  bxMax.text           := inttostr(maxs);
  bxMid.text           := formatfloat('0.0',midscore);
  bxGreen.text         := bxMax.text;
  bxRed.text           := inttostr(red);
  bxOrange.text        := inttostr(orange); 
  cancelled := true;
  if modal then showmodal else show;


end;

initialization
  {$I setup.lrs}

end.

